﻿#region COPYRIGHT
//--------------------------------------------------------------------------------
// <copyright file="CircleF.cs" company="starLiGHT Entertainment Studios">
//    Copyright (c) 2010 
//       Roland Rosenkranz (Glatzemann@email.de)
// </copyright>
// <license>
//   This file is part of starLiGHT.Core.
//
//   starLiGHT.Core is free software: you can redistribute it and/or modify
//   it under the terms of the GNU Lesser General Public License as published by
//   the Free Software Foundation, either version 3 of the License, or
//   (at your option) any later version.
//
//   starLiGHT.Core is distributed in the hope that it will be useful,
//   but WITHOUT ANY WARRANTY; without even the implied warranty of
//   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//   GNU Lesser General Public License for more details.
//
//   You should have received a copy of the GNU Lesser General Public License
//   along with starLiGHT.Core. If not, see http://www.gnu.org/licenses/.
//    
//   ADDITIONAL (commercial) LICENSES for starLiGHT.Core are available on request.
// </license>
// <version>
// **************[ starLiGHT.Engine SVN ]**********************
// * $Rev:: 620                   $:  Revision of last commit *
// * $Author:: unknown            $:  Author of last commit   *
// * $Date:: 2010-12-07 15:23:58 #$:  Date of last commit     *
// ************************************************************
// </version>
//--------------------------------------------------------------------------------
#endregion

namespace starLiGHT
{
    #region Using Statements
    using System;
    using System.Collections.Generic;
    using System.Text;
    using Microsoft.Xna.Framework;
    #endregion

    /// <summary>
    /// A circle with Float-Position and radius.
    /// Used for Bounding checks e.g.
    /// </summary>
    public struct CircleF
    {
        private Vector2 center;
        private float radius;

        public CircleF(Vector2 center, float radius)
        {
            this.center = center;
            this.radius = radius;
        }

        public CircleF(RectangleF fromRectangle)
        {
            this.center = fromRectangle.Center;
            this.radius = Vector2.Distance(fromRectangle.Center, fromRectangle.TopLeft);
        }

        public Vector2 Center
        {
            get { return this.center; }
            set { this.center = value; }
        }

        public float Radius
        {
            get { return this.radius; }
            set { this.radius = value; }
        }

        public bool IsEmpty
        {
            get { return this.center == Vector2.Zero && this.radius == 0f; }
        }

        /// <summary>
        /// Determines whether a specified CircleF intersects with this CircleF. 
        /// </summary>
        /// <param name="other">The CircleF to evaluate.</param>
        /// <returns>true if the specified CircleF intersects with this one; false otherwise.</returns>
        public bool Intersects(CircleF other)
        {
            float dist = float.MaxValue;
            Vector2.Distance(ref this.center, ref other.center, out dist);
            return this.radius + other.radius >= dist;
        }

        /// <summary>
        /// Determines whether a specified CircleF intersects with this CircleF. 
        /// </summary>
        /// <param name="other">The CircleF to evaluate.</param>
        /// <param name="result">true if the specified CircleF intersects with this one; false otherwise.</param>
        public void Intersects(ref CircleF other, out bool result)
        {
            float dist = float.MaxValue;
            Vector2.Distance(ref this.center, ref other.center, out dist);
            result = this.radius + other.radius >= dist;
        }

        /// <summary>
        /// Determines whether a specified RectangleF intersects with this CircleF. 
        /// </summary>
        /// <param name="other">The RectangleF to evaluate.</param>
        /// <returns>true if the specified RectangleF intersects with this CircleF; false otherwise.</returns>
        public bool Intersects(RectangleF other)
        {
            float w = other.Width * 0.5f;
            float h = other.Height * 0.5f;

            float dx = Math.Abs(this.center.X - other.Center.X);
            float dy = Math.Abs(this.center.Y - other.Center.Y);

            if (dx > (this.radius + w) || dy > (this.radius + h))
            {
                return false;
            }

            float cdX = Math.Abs(this.center.X - other.Center.X - w);
            float cdY = Math.Abs(this.center.Y - other.Center.Y - h);

            if (cdX <= w || cdY <= h)
            {
                return true;
            }

            float cornerDistanceSqr = ((cdX - w) * (cdX - w)) + ((cdY - h) * (cdY - h));

            return cornerDistanceSqr <= this.radius * this.radius;
        }

        /// <summary>
        /// Determines whether a specified RectangleF intersects with this CircleF. 
        /// </summary>
        /// <param name="other">The RectangleF to evaluate.</param>
        /// <param name="result">
        /// true if the specified RectangleF intersects with this CircleF; false otherwise.
        /// </param>
        public void Intersects(ref RectangleF other, out bool result)
        {
            float w = other.Width * 0.5f;
            float h = other.Height * 0.5f;

            float dx = Math.Abs(this.center.X - other.Center.X);
            float dy = Math.Abs(this.center.Y - other.Center.Y);

            if (dx > (this.radius + w) || dy > (this.radius + h))
            {
                result = false;
                return;
            }

            float cdX = Math.Abs(this.center.X - other.Center.X - w);
            float cdY = Math.Abs(this.center.Y - other.Center.Y - h);

            if (cdX <= w || cdY <= h)
            {
                result = true;
                return;
            }

            float cornerDistanceSqr = ((cdX - w) * (cdX - w)) + ((cdY - h) * (cdY - h));

            result = cornerDistanceSqr <= this.radius * this.radius;
        }
    }
}
